package cn.zyl.demo.common.tools;

import cn.zyl.demo.common.enums.FontFileTypeEnum;
import cn.zyl.demo.common.enums.FontStyleEnum;
import cn.zyl.demo.common.exception.BeansException;

import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GraphicsEnvironment;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** FontTool 工具类说明: 字体工具类
 * <p>
 *     参考网址：<br>
 *     <a href="http://tool.httpcn.com/">汉程字典</a><br>
 *     <a href="https://unicode-table.com/cn/">Unicode 字符百科</a><br>
 *     <a href="https://www.qqxiuzi.cn/zh/hanzi-unicode-bianma.php">汉字 Unicode 编码范围</a><br>
 *     <a href="https://www.cnblogs.com/crazylqy/p/10184291.html">彻底弄懂 Unicode 编码</a><br>
 * </p>
 *<pre>
 *     字符集 	字数 	Unicode 编码
 *     基本汉字 	20902字 	4E00-9FA5
 *     基本汉字补充 	74字 	9FA6-9FEF
 *     扩展A 	6582字 	3400-4DB5
 *     扩展B 	42711字 	20000-2A6D6
 *     扩展C 	4149字 	2A700-2B734
 *     扩展D 	222字 	2B740-2B81D
 *     扩展E 	5762字 	2B820-2CEA1
 *     扩展F 	7473字 	2CEB0-2EBE0
 *     扩展G 	4939字 	30000-3134A
 *     康熙部首 	214字 	2F00-2FD5
 *     部首扩展 	115字 	2E80-2EF3
 *     兼容汉字 	477字 	F900-FAD9
 *     兼容扩展 	542字 	2F800-2FA1D
 *     PUA(GBK)部件 	81字 	E815-E86F
 *     部件扩展 	452字 	E400-E5E8
 *     PUA增补 	207字 	E600-E6CF
 *     汉字笔画 	36字 	31C0-31E3
 *     汉字结构 	12字 	2FF0-2FFB
 *     汉语注音 	43字 	3105-312F
 *     注音扩展 	22字 	31A0-31BA
 *     〇 	1字 	3007
 *</pre>
 * @author wsz
 * @date 2020-08-18
 * @version v1.0
 */
public class FontTool {
    private FontTool(){throw new IllegalAccessError("FontTool");}
    /** 特殊字体，不能显示普通英文字符*/
    public static final String[] SPECIAL_FONT={"Amiri Quran","Bookshif Symbol 7","EmpjiOne Color","Hololens MDL2 Assets"};

    private static String[] getFonts(){
        //返回本地 GraphicsEnvironment
        GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
        //返回包含在此所有字体系列名称的数组， GraphicsEnvironment本地化为默认的语言环境，如返回 Locale.getDefault()
        return environment.getAvailableFontFamilyNames();
    }
    /**
     * 判定输入的是否是汉字
     * @param c 被校验的字符
     * @return true代表是汉字
     */
    public static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS;
    }
    /**
     * 校验String是否全是中文
     * @param name 被校验的字符串
     * @return true代表全是汉字
     */
    public static boolean isChinese(String name) {
        boolean res = true;
        char[] cTemp = name.toCharArray();
        for (int i = 0; i < name.length(); i++) {
            if (!isChinese(cTemp[i])) {
                res = false;
                break;
            }
        }
        return res;
    }
    /**
     * 校验某个字符是否是a-z、A-Z、_、0-9
     * @param c 被校验的字符
     * @return true代表符合条件
     */
    public static boolean isWord(char c) {
        String regEx = "[\\w]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher("" + c);
        return m.matches();
    }
    /**
     * 判断字符串中是否包含中文
     * @param str 待校验字符串
     * @return 是否为中文,不能校验是否为中文标点符号
     */
    public static boolean isContainChinese(String str) {
        String regEx = "[\u4e00-\u9fa5]";
        Pattern pattern = Pattern.compile(regEx);
        Matcher m = pattern.matcher(str);
        return m.find();
    }
    /**
     * 过滤掉中文
     * @param str 待过滤中文的字符串
     * @return 过滤掉中文后字符串
     */
    public static String filterChinese(String str) {
        // 包含中文
        if (isContainChinese(str)) {
            // 用于拼接过滤中文后的字符
            StringBuilder sb = new StringBuilder();
            // 5.去除掉文件名中的中文,将字符串转换成char[]
            for (char c : str.toCharArray()) {
                // 不是中日韩文字及标点符号
                if (!isChinese(c)) {
                    sb.append(c);
                }
            }
            return sb.toString();
        }
        return str;
    }
    /** 判断字体支持中文的字符范围（41个位置点），-2字体为null;-1不支持中文;>=0支持中文程度不同 */
    public static int canDisplayChinaAll(Font font){
        int tags = -2;
        if(null == font) {return tags;}
        tags ++;
        //完整的中文Unicode范围点，41个
        int[] text = {
                /*部首扩展*/
                0x2E80,0x2EF3,
                /*康熙部首*/
                0x2F00,0x2FD5,
                /*汉字结构*/
                0x2FF0,0x2FFB,
                /*〇*/
                0x3007,
                /*汉语注音*/
                0x3105,0x312F,
                /*注音扩展*/
                0x31A0,0x31BA,
                /*汉字笔画*/
                0x31C0,0x31E3,
                /*扩展A*/
                0x3400,0x4db5,
                /*基本汉字*/
                0x4e00,0x9fa5,
                /*基本汉字补充*/
                0x9fa6,0x9fef,
                /*部件扩展*/
                0xE400,0xE5E8,
                /*PUA增补*/
                0xE600,0xE6CF,
                /*PUA(GBK)部件*/
                0xE815,0xE86F,
                /*兼容汉字*/
                0xF900,0xFAD9,
                /*扩展B*/
                0x20000,0x2A6D6,
                /*扩展C*/
                0x2A700,0x2B734,
                /*扩展D*/
                0x2B740,0x2B81D,
                /*扩展E*/
                0x2B820,0x2CEA1,
                /*扩展F*/
                0x2CEB0,0x2EBE0,
                /*兼容扩展*/
                0x2F800,0x2FA1D,
                /*扩展G*/
                0x30000,0x3134A,
        };
        for (int c : text) {
            if(font.canDisplay(c)){
                //判断字体是否可以显示当前字符
                tags ++;
            }
        }
        return tags;
    }

    /**
     * 获取当前系统支持的字体
     * @return 字体名称列表
     */
    public static List<String> supportFontNames(){
        String[] fontNames = getFonts();
        return Arrays.asList(fontNames);
    }
    /**
     * 获取当前系统支持中文的字体
     * @return 字体名列表
     */
    public static List<String> supportChineseFonts(){
        String[] fontNames = getFonts();
        List<String> names = new ArrayList<>();
        Font font;
        //循环输出，并判断是否支持中文
        for (String name : fontNames) {
            //创建字体
            font = new Font(name, Font.PLAIN, 10);
            if(canDisplayChinaAll(font) >= 0){
                names.add(name);
            }
        }
        return names;
    }
    /**
     * 获取当前系统支持英文的字体
     * @return 字体名列表
     */
    public static List<String> supportEnglishFonts(){
        String[] fontNames = getFonts();
        List<String> names = new ArrayList<>();
        Font font;
        //循环输出，并判断是否支持英文
        for (String name : fontNames) {
            //创建字体
            font = new Font(name, Font.PLAIN, 10);
            if(font.canDisplay('a')){
                names.add(name);
            }
        }
        return names;
    }

    /**
     * 随机获取字体
     * @param style 字体样式，null-》普通字体
     * @param fontSize 字体大小,大于零
     * @param china true 只随机支持中文的；false 随机全部字体
     * @return 字体对象
     */
    @SuppressWarnings("MagicConstant")
    public static Font randomFont(FontStyleEnum style, int fontSize, boolean china){
        if( null == style ){ style = FontStyleEnum.PLAIN; }
        if( fontSize <= 0 ){ fontSize = 0; }
        List<String> names = china ? supportChineseFonts() : supportEnglishFonts();
        Random random = new Random();
        String name = names.get(random.nextInt(names.size()));
        return new Font(name, style.ordinal(), fontSize);
    }

    /**
     * 加载指定路径下的字体文件
     * <p>避免产生.tmp临时文件，避免大批量引入的时候吃掉硬盘的空间</p>
     * <pre>
     *     //第二种方式：实现方法–注意会产生.tmp临时文件
     *      File file = new File(filepath);
     *      FileInputStream fi = new FileInputStream(file);
     *      BufferedInputStream fb = new BufferedInputStream(fi);
     *      Font font = java.awt.Font.createFont(Font.TRUETYPE_FONT, fb).deriveFont(Font.PLAIN, 40);
     * </pre>
     * @param filePath 文件路径，不含文件名,最好使用前缀 ./ 项目根路径
     * @param fileName 字体文件名，不带后缀
     * @param type 字体文件格式
     * @return 字体对象，当前样式 font.deriveFont(Font.PLAIN, 10);
     */
    public static Font loadSelfFontFile(String filePath, String fileName, FontFileTypeEnum type)throws BeansException{
        BeansException.isTrueThrow(StringTool.isEmpty(filePath), "font file path is empty.");
        BeansException.isTrueThrow(StringTool.isEmpty(fileName), "font file name is empty.");
        StringBuilder fontPath = new StringBuilder();
        //如果开始字符是/，则是项目相对路径
        if(filePath.startsWith(FileTool.SKIP_PEER_PREFIX)){
            if(!filePath.startsWith(FileTool.SKIP_FATHER_PREFIX)){
                filePath = filePath.substring(1);
            }
            fontPath.append(FileTool.relativeToAbsolutelyByPath(filePath)).append(File.separator);
        }else{
            fontPath.append(filePath).append(File.separator);
        }
        if(null == type) { type = FontFileTypeEnum.TTF; }
        fontPath.append(fileName).append(".").append(type.name());
        return loadSelfFontFile(fontPath.toString());
    }
    private static Font loadSelfFontFile(String fontPath)throws BeansException{
        try {
            BeansException.isTrueThrow(StringTool.isEmpty(fontPath), "font file is empty.");
            File file = new File(fontPath);
            BeansException.isTrueThrow(!file.exists(), "font file is not exists.");
            //根据字体文件所在位置,创建新的字体对象
            return Font.createFont(Font.TRUETYPE_FONT, file).deriveFont(Font.PLAIN, 10);
        } catch (FontFormatException | IOException e) {
            throw new BeansException(e);
        }
    }
    public static void main(String[] args) {
        System.out.println(isWord('测'));
        System.out.println(isWord('1'));
        System.out.println(isChinese('测'));
        // 一
        System.out.println(isChinese((char)0x4E00));
        //龥
        System.out.println(isChinese((char)0x9FA5));
        System.out.println(isChinese('1'));
        System.out.println(isChinese("ce shi测试>{(*)(*"));
        System.out.println(isChinese("ce shi13213>{(*)(*"));
        System.out.println(filterChinese("ce shi测试>{(*)(*"));
        System.out.println(2& ~0x03);
        System.out.println(FontStyleEnum.BOLD.ordinal());
        System.out.println(6& ~0x03);
        //System.out.println(randomFont(FontStyleEnum.BOLD,10,false).getName());
        //System.out.println(randomFont(FontStyleEnum.BOLD_ITALIC,10,true).getName());
        //System.out.println(supportFontNames().size());
        //System.out.println(getFonts().length);
        //System.out.println(supportEnglishFonts().size());
        //D:\_project\IDEA-2020-1\sb-j8-mp-jd\common\src\main
        System.out.println(FileTool.relativeToAbsolutelyByPath("/fonts"));
        System.out.println(FontTool.class.getResource("./").getPath());
        System.out.println(loadSelfFontFile("./fonts", "JOKERMAN", FontFileTypeEnum.TTF).getName());
//        String[] fontNames = getFonts();
//        Font font;
//        for (String name : fontNames) {
//            font = new Font(name, Font.PLAIN, 10);
//            System.out.print(canDisplayChinaAll(font));
//            System.out.print("=======");
//            System.out.println(name);
//        }
    }
}